package com.simple.sso.server.controller;

import com.simple.sso.client.entity.User;
import com.simple.sso.client.utils.HttpUtils;
import com.simple.sso.client.utils.SessionStorage;
import com.simple.sso.server.utils.ClientStorage;
import com.simple.sso.server.utils.JsonResult;
import com.simple.sso.server.utils.JsonStatus;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

@Controller
@RequestMapping
public class LoginController {

    @GetMapping(value = {"/", "/login"})
    public String login() {
        return "login";
    }

    @PostMapping(value = "/doLogin")
    @ResponseBody
    public JsonResult doLogin(User user, HttpServletRequest request) {
        JsonResult jsonResult = new JsonResult();
        if ("zhangsan".equals(user.getUserName()) && "000000".equals(user.getPassword())) {

            //登录成功，设置session，生成令牌
            HttpSession session = request.getSession();
            String token = UUID.randomUUID().toString();
            session.setAttribute("isLogin", true);
            session.setAttribute("token", token);
            //存储全局token和session映射关系，注销时使用
            SessionStorage.INSTANCE.set(token, session);
            jsonResult.setJsonStatus(JsonStatus.SUCCESS);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            jsonResult.setResultMap(resultMap);
            jsonResult.setMsg("登录成功！");
        }

        return jsonResult;
    }

    /**
     * 注销登录思路：
     * 1、认证中心现在是登录状态，session可以直接获取到单点登录用到的token令牌；
     * 2、ClientStorage中存储着使用token令牌登录的所有子系统，注销登录时循环调用各个子系统的请求，依次实现子系统的局部session；
     * 3、如何区分客户端发起的注销请求还是认证中心发起的注销请求？
     * 子系统主动发起注销，使用httpClient调用认证中心的登出请求，url中携带参数logoutRequest=token；
     * 认证中心注销，则会调用客户端请求，通过LogoutFilter清除各个子系统的session，实现登出；
     */
    @RequestMapping(value = "/logout")
    @ResponseBody
    public JsonResult logout(HttpServletRequest request) {
        System.out.println("execute sso-server logout method....");
        JsonResult jsonResult = new JsonResult();
        HttpSession session = request.getSession();

        //判断是否为子系统主动登出
        String token = request.getParameter("logoutRequest");
        if (!StringUtils.isEmpty(token)) {
            //获取全局session
            session = SessionStorage.INSTANCE.removeAndGetSession(token);
        } else {
            token = (String) session.getAttribute("token");
        }

        //注销全局session
        if (session != null) {
            session.invalidate();
            System.out.println("------>>全局session失效成功！");
        }

        //获取token对应的客户端请求url
        Set<String> clientUrlSet = ClientStorage.INSTANCE.getClientUrl(token);
        if (clientUrlSet != null) {
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("logoutRequest", token);
            for (String clientUrl : clientUrlSet) {
                boolean isSuccess = HttpUtils.post(clientUrl, paramMap);
                if (isSuccess) {
                    jsonResult.setMsg("登出成功！");
                    jsonResult.setJsonStatus(JsonStatus.SUCCESS);
                }
            }
        }

        return jsonResult;
    }

    @RequestMapping(value = "checkTokenValid")
    @ResponseBody
    public boolean checkTokenValid(HttpServletRequest request) {
        System.out.println("checkTokenValid开始执行了。。。");
        String token = request.getParameter("token");
        return SessionStorage.INSTANCE.getSession(token) != null;
    }

    @GetMapping(value = "/success")
    public String success() {
        return "success";
    }
}
